﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Transactions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Ue.Infrastructure.Data;

namespace Ue.Tests.Infrastructure.Data
{
    /// <summary>
    /// UnitOfWork 的摘要说明
    /// </summary>
    [TestClass]
    public class UnitOfWorkTests
    {
        private Mock<IUnitOfWorkRepository<IEntity<int>, int>> mockRepository;
        private Mock<IEntity<int>> mockEntity;
        private IUnitOfWork unitOfWork = new UnitOfWork();
        private int changeCount = 0,
                    addCount = 0,
                    deleteCount = 0;

        [TestInitialize]
        public void Initial()
        {
            this.mockEntity = new Mock<IEntity<int>>();
            this.mockRepository = new Mock<IUnitOfWorkRepository<IEntity<int>, int>>();

            this.mockRepository.Setup(item => item.PersistUpdatedItem(It.IsAny<IEntity<int>>())).Callback(() => ++changeCount);
            this.mockRepository.Setup(item => item.PersistDeletedItem(It.IsAny<IEntity<int>>())).Callback(() => ++deleteCount);
            this.mockRepository.Setup(item => item.PersistNewItem(It.IsAny<IEntity<int>>())).Callback(() => ++addCount);
        }

        /// <summary>
        /// 所有的操作在提交Commit时才执行。
        /// </summary>
        [TestMethod]
        public void PerformedAfteTheCommited()
        {
            this.unitOfWork.RegisterAdded(mockEntity.Object,mockRepository.Object);
            this.unitOfWork.RegisterDeleted(mockEntity.Object, mockRepository.Object);
            this.unitOfWork.RegisterModified(mockEntity.Object, mockRepository.Object);

            Assert.AreEqual(0, this.addCount);
            Assert.AreEqual(0, this.changeCount);
            Assert.AreEqual(0, this.deleteCount);

            this.unitOfWork.Commit();
            Assert.AreEqual(1, this.addCount);
            Assert.AreEqual(1, this.deleteCount);
            Assert.AreEqual(1, this.changeCount);
        }

        /// <summary>
        /// 先执行需要删除的对象
        /// 再执行添加的对象
        /// 最后执行更新的对象
        /// </summary>
        [TestMethod]
        public void FirstDeleteLastUpdate()
        {
            this.mockRepository.Setup(item => item.PersistUpdatedItem(It.IsAny<IEntity<int>>())).Callback(() =>
            {
                changeCount++;
                Assert.AreEqual(1, changeCount);
                Assert.AreEqual(1,deleteCount);
                Assert.AreEqual(1,addCount);
            });
            this.mockRepository.Setup(item => item.PersistDeletedItem(It.IsAny<IEntity<int>>())).Callback(() =>
            {
                ++deleteCount;

                Assert.AreEqual(1,deleteCount);
                Assert.AreEqual(0,addCount);
                Assert.AreEqual(0,changeCount);
            });
            this.mockRepository.Setup(item => item.PersistNewItem(It.IsAny<IEntity<int>>())).Callback(() =>
            {
                ++addCount;

                Assert.AreEqual(1, deleteCount);
                Assert.AreEqual(1, addCount);
                Assert.AreEqual(0, changeCount);
            });

            this.unitOfWork.RegisterModified(mockEntity.Object, mockRepository.Object);
            this.unitOfWork.RegisterDeleted(mockEntity.Object, mockRepository.Object);
            this.unitOfWork.RegisterAdded(mockEntity.Object, mockRepository.Object);

            this.unitOfWork.Commit();
        }

        [TestMethod]
        public void OnlyOneAddToWorkCaches()
        {
            this.unitOfWork.RegisterAdded(mockEntity.Object, mockRepository.Object);
            this.unitOfWork.RegisterAdded(mockEntity.Object, mockRepository.Object);
            this.unitOfWork.RegisterAdded(mockEntity.Object, mockRepository.Object);
            this.unitOfWork.RegisterAdded(mockEntity.Object, mockRepository.Object);

            this.unitOfWork.Commit();
            Assert.AreEqual(1,addCount);
        }

        ///// <summary>
        ///// 当同一个对象注册为删除时，
        ///// 那么在之前注册的其它操作将被取消
        ///// </summary>
        //[TestMethod]
        //public void AddedBeforeDeletingByRegisterRemove()
        //{
        //    this.unitOfWork.RegisterAdded(mockEntity.Object, mockRepository.Object);
        //}
    }
}
